package com.tensquare.manager.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import util.JwtUtil;
import javax.servlet.http.HttpServletRequest;

/**
 * @author Macross
 * @Type ManagerFilter.java
 * @Desc 后台网关过滤器
 * @date 2019/12/27 12:10
 */
@Component
public class ManagerFilter extends ZuulFilter {

    @Autowired
    private JwtUtil jwtUtil;

    /**
     * 设置过滤器类型
     * @return
     */
    @Override
    public String filterType() {
        //设置类型为pre,代表在执行网关路由前被调用
        return "pre";
    }

    /**
     * 设置过滤器的顺序级别,越小优先级越高
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 设置是否开启该过滤器
     * @return
     */
    @Override
    public boolean shouldFilter() {
        //开启过滤器
        return true;
    }

    /**
     * 过滤器执行方法,必须返回对象,否则不会继续往下执行,返回null也可以
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //获取当前请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求对象request
        HttpServletRequest request = currentContext.getRequest();
        /**
         * 在访问子微服务进行跨域请求的时候，并且请求头中有额外参数，比如token，客户端会先发送一个OPTIONS请求,
         * 来探测后续需要发起的跨域POST请求是否安全可接受,所以OPTIONS请求直接放行
         */
        if (StringUtils.equals(request.getMethod(),"OPTIONS")) {
            //直接放行
            return null;
        }
        //判断当前请求URL是否为登录url
        if (StringUtils.contains(request.getRequestURL().toString(),"/login")) {
            //直接放行
            return null;
        }
        //获取请求头
        String header = request.getHeader("Authorization");
        //判断请求头是否为空
        if (StringUtils.isNotBlank(header)) {
            //判断请求头是否以bearer 开头
            if (header.startsWith("bearer ")) {
                //截取字符串,获取token
                String token = header.substring(7);
                //解析token,获取claims对象
                Claims claims = jwtUtil.parseToken(token);
                //判断claims对象是否为空
                if (claims != null) {
                    //获取角色信息
                    String roles = (String) claims.get("roles");
                    //判断角色是否为admin
                    if (StringUtils.equals("admin",roles)){
                        //将获取到的请求头放入zuul网关请求头中
                        /**
                         * 需要注意:
                         *  敏感头信息Authorization,Cookie,Set-Cookie默认是不转发的,
                         * 在配置文件里设置zuul.sensitiveHeaders为空，就可以获取到了[什么都不设置代表不过滤任何信息]
                         */
                        currentContext.addZuulRequestHeader("Authorization",header);
                        //放行
                        return null;
                    }
                }
            }
        }
        /**
         * 当前请求并不是登录请求,也不是OPTIONS请求方式,并且没有授权或并非admin权限时会执行以下代码
         */
        //取消发送网关响应,也就是取消继续执行
        currentContext.setSendZuulResponse(false);
        //设置响应状态码为403(401也可以)
        currentContext.setResponseStatusCode(403);
        //输出到网页的信息
        currentContext.setResponseBody("无权访问");
        //设置contentType
        currentContext.getResponse().setContentType("text/html;charset=utf-8");
        //放行
        return null;
    }
}
